package com.os.opencv.java.chapter13;

import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Scalar;
import org.opencv.highgui.HighGui;
import org.opencv.imgproc.Imgproc;
import org.opencv.video.Video;
import org.opencv.videoio.VideoCapture;

import java.util.ArrayList;
import java.util.Arrays;

public class OpticalFlowFB {

    public static void main(String[] args) {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

        //打开时视屏文件
        VideoCapture vc = new VideoCapture();
        vc.open("pics/2023-11-29_19-50-14.mp4");

        //视屏打开失败时的处理
        if(!vc.isOpened()){
            System.out.println("unable to load video!");
            System.exit(-1);
        }

        //读取原始图像frame0
        Mat frame0 = new Mat();
        Mat prev = new Mat();
        vc.read(frame0);
        Imgproc.cvtColor(frame0, prev, Imgproc.COLOR_BGR2GRAY);

        while(true){
            //读取新画面frame
            Mat frame = new Mat();
            vc.read(frame);

            //视屏文件读取完毕，则退出循环
            if(frame.empty()){
                break;
            }

            //将frame转换为灰度图
            Mat next = new Mat();
            Imgproc.cvtColor(frame, next, Imgproc.COLOR_BGR2GRAY);

            //计算稠密灌流
            int type = CvType.CV_32FC2;
            Mat flow = new Mat(prev.size(), type);
            Video.calcOpticalFlowFarneback(prev, next, flow, 0.5, 3, 15, 3, 5, 1.2, 0);

            //将flow按通道拆分
            ArrayList<Mat> flow2c = new ArrayList<>(2);
            Core.split(flow, flow2c);

            //计算幅值和角度
            Mat magnitude = new Mat();
            Mat angle = new Mat();
            Core.cartToPolar(flow2c.get(0), flow2c.get(1), magnitude, angle, true);

            //归一化
            Mat mag = new Mat();
            int nm = Core.NORM_MINMAX;
            Core.normalize(magnitude, mag, 0, 1, nm);

            //将幅值和角度生成hsv颜色空间的图像
            float f = (float) (180.0/255.0/360.0);
            Mat angle2 = new Mat();
            Core.multiply(angle, new Scalar(f), angle2);

            //将3个通道图像合并
            ArrayList<Mat> hsv3c = new ArrayList<>();
            hsv3c.add(angle2);
            hsv3c.add(Mat.ones(angle.size(), CvType.CV_32F));
            hsv3c.add(mag);
            Mat hsv = new Mat();
            Core.merge(hsv3c, hsv);

            //转换为RGB颜色空间
            Mat hsv2 = new Mat();
            Mat bgrImg = new Mat();
            hsv.convertTo(hsv2, CvType.CV_8U, 255.0);
            Imgproc.cvtColor(hsv2, bgrImg, Imgproc.COLOR_HSV2BGR);

            //在屏幕上显示跟踪结果
            HighGui.imshow("frame", bgrImg);
            int keyBoard = HighGui.waitKey(60);

            //按esc键退出
            if(keyBoard == 27) break;
            prev = next;  //更新图像
        }
        HighGui.waitKey(0);
    }
}
